<?php
/**
 * 公共函数类
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/11/20
 * Time: 16:00
 */
namespace app\common\controller;
use think\Db;
class CommonFun  {
    /**
     * 数据掩盖
     * @param $str
     * @param $start
     * @return mixed
     */
    public static function replaceStar($str, $start) {
        $length = (int)(strlen($str) / 2);
        $i = 0;
        $star = '';
        if($start >= 0) {
            if($length > 0) {
                $str_len = strlen($str);
                $count = $length;
                if($start >= $str_len) {//当开始的下标大于字符串长度的时候，就不做替换了
                    $count = 0;
                }
            }elseif($length < 0){
                $str_len = strlen($str);
                $count = abs($length);
                if($start >= $str_len) {//当开始的下标大于字符串长度的时候，由于是反向的，就从最后那个字符的下标开始
                    $start = $str_len - 1;
                }
                $offset = $start - $count + 1;//起点下标减去数量，计算偏移量
                $count = $offset >= 0 ? abs($length) : ($start + 1);//偏移量大于等于0说明没有超过最左边，小于0了说明超过了最左边，就用起点到最左边的长度
                $start = $offset >= 0 ? $offset : 0;//从最左边或左边的某个位置开始
            }else {
                $str_len = strlen($str);
                $count = $str_len - $start;//计算要替换的数量
            }
        }else {
            if($length > 0) {
                $offset = abs($start);
                $count = $offset >= $length ? $length : $offset;//大于等于长度的时候 没有超出最右边
            }elseif($length < 0){
                $str_len = strlen($str);
                $end = $str_len + $start;//计算偏移的结尾值
                $offset = abs($start + $length) - 1;//计算偏移量，由于都是负数就加起来
                $start = $str_len - $offset;//计算起点值
                $start = $start >= 0 ? $start : 0;
                $count = $end - $start + 1;
            }else {
                $str_len = strlen($str);
                $count = $str_len + $start + 1;//计算需要偏移的长度
                $start = 0;
            }
        }

        while ($i < $count) {
            $star .= '*';
            $i++;
        }

        return substr_replace($str, $star, $start, $count);
    }

    /**
     * 精确数字位数
     * @param int $num 数字字串
     * @param int $decimal 保留的小树位数
     * @return int 返回处理过的数字字串
     */
    public static function numberFormat($num, $decimal){
        return number_format($num, $decimal, '.', '');
    }

    // public static function numberFormat($num, $decimal){
    //     return number_format($num, $decimal, '.', '');
    // }

    /**
     * IP地址
     */
    public static function get_ip(){
        if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) and @$_SERVER["HTTP_X_FORWARDED_FOR"])
            $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        else if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) and @$_SERVER["HTTP_CLIENT_IP"])
            $ip = $_SERVER["HTTP_CLIENT_IP"];
        else if (@$_SERVER["REMOTE_ADDR"])
            $ip = $_SERVER["REMOTE_ADDR"];
        else if (@getenv("HTTP_X_FORWARDED_FOR"))
            $ip = getenv("HTTP_X_FORWARDED_FOR");
        else if (@getenv("HTTP_CLIENT_IP"))
            $ip = getenv("HTTP_CLIENT_IP");
        else if (@getenv("REMOTE_ADDR"))
            $ip = getenv("REMOTE_ADDR");
        else
            $ip = "Unknown";

        $start=strpos($ip, '::ffff:');
        if($start !== false)
        {
            $ip = substr($ip, $start+7);
        }

        return $ip;
    }


    /**
     * 判断是否是移动端.
     * @return bool
     */
    public static function isMobile(){
        // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
        if (isset ($_SERVER['HTTP_X_WAP_PROFILE'])){
            return TRUE;
        }
        // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
        //if (isset ($_SERVER['HTTP_VIA'])){
        //    return stristr($_SERVER['HTTP_VIA'], "wap") ? TRUE : FALSE;// 找不到为flase,否则为TRUE
        //}
        // 判断手机发送的客户端标志,兼容性有待提高
        if (isset ($_SERVER['HTTP_USER_AGENT'])) {
            $clientkeywords = array ('mobile','nokia','sony','ericsson','mot','samsung','htc','sgh','lg','sharp','sie-','philips','panasonic','alcatel','lenovo','iphone','ipod','blackberry','meizu','android','netfront','symbian','ucweb','windowsce','palm','operamini','operamobi','openwave','nexusone','cldc','midp','wap'
            );
            // 从HTTP_USER_AGENT中查找手机浏览器的关键字
            if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))){
                return TRUE;
            }
        }
        if (isset ($_SERVER['HTTP_ACCEPT'])){ // 协议法，因为有可能不准确，放到最后判断
            // 如果只支持wml并且不支持html那一定是移动设备
            // 如果支持wml和html但是wml在html之前则是移动设备
            if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== FALSE) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === FALSE || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))){
                return TRUE;
            }
        }
        return FALSE;
    }


    /**
     * 交易号生产
     * @param string $fn|前缀字串
     * @return string 交易号字串
     */
    public static function CreateWaterNo($fn=''){
        $billNo = $fn . substr(time(),-9) . self::GetRandomString(8,0);
        return $billNo;
    }

    /**
     * 交易号生产
     * @param string $fn 前缀字串
     * @return string 交易号字串
     */
    public static function CreateBillNo($fn = ''){
        $billNo = $fn . date('YmdHis') . self::GetRandomString(8,0);
        return $billNo;
    }

    /**
     * 随机字串生成
     * @param int $len 长度
     * @param int $p 是否是用字母
     * @return string 随机字串
     */
    public static function GetRandomString($len, $p=1){
        if ($p){
            $chars = array('q','w','e','r','t','y','u','i','o','p','a','s','d','f','g','h','j','k','l','z','x','c','v','b','n','m');
        }else{
            $chars = array('1','0','2','3','4','5','6','7','9');
        }
        $charsLen = count($chars) - 1;
        shuffle($chars); //将数组打乱
        $output = '';
        for ($i = 0; $i < $len; $i ++){
            $output .= $chars[mt_rand(0,$charsLen)];
        }
        return $output;
    }



    /**
     * 返回时间
     * @param string $type 时间格式
     * @param string $change 变更时间
     * @return bool|string
     */
    public static function GetTime($type = '', $change = '')
    {
        if($type == '')
            $type = 'Y-m-d H:i:s';
        if($change != '')
            return date($type,strtotime($change));
        return date($type);
    }

    /**
     * 校验数组值是否设置，未设置返回''
     * @param string $arr
     * @param string $key
     * @return string
     */
    public static function CheckArrValue($arr, $key)
    {
        $value = '';
        if(isset($arr[$key]))
            $value = $arr[$key];
        return $value;
    }

    /**
     * 数组以某一个key的值去重复功能
     * @param $arr
     * @param $key
     * @return mixed
     */
    public static function assoc_unique($arr, $key) {
        $tmp_arr = array();
        foreach($arr as $k => $v) {
            if(in_array($v[$key], $tmp_arr)) {
                unset($arr[$k]);
            } else {
                $tmp_arr[] = $v[$key];
            }
        }
        sort($arr);
        return $arr;
    }

    /**
     * 根据表名获取状态列表
     * @param $table
     * @return array
     */
    public static function GetStateListByTable($table)
    {
        $rows = Db::name($table)->select();
        $arr_return = array();
        foreach($rows as $value){
            $arr_return[$value['id']] = $value['note'];
        }
        return $arr_return;
    }

    /**
     * 作用：以post方式提交xml到对应的接口url
     * @param array $post_data  Post数据
     * @param string $url 发送地址
     * @param string $hostUrl 设置host
     * @param int $second 设置超时
     * @return bool|mixed
     */
    public static function PostCurl($post_data ,$url ,$hostUrl='' ,$second=30){
        //初始化curl
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        //这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch,CURLOPT_URL, $url);
        // curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        // curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
        if($hostUrl != ''){
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: '.$hostUrl));
        }
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if($data) {
            curl_close($ch);
            return $data;
        }else{
            // echo $error = curl_errno($ch);
            return false;
        }
    }


    /**
     * 将二维数组以 一个key为主 构成 以key值为分组的 三维数组，可以将需要显示的字段放入分组的数组
     * @param array $arr            目标二维数组
     * @param string $key_name      分组的key名
     * @param string $class_keys    需要显示在分组下的 key名
     * @return array
     */
    public static function ArrayToClassByKey($arr, $key_name, $class_keys = '' )
    {
        $arr_class_key = explode(',', $class_keys);
        $arr_return = array();
        foreach($arr as $value){
            if($class_keys != ''){
                foreach($arr_class_key as $value_class_key){
                    $arr_return[$value[$key_name]][$value_class_key] = $value[$value_class_key];
                }
            }
            $arr_return[$value[$key_name]][$key_name] = $value[$key_name];
            $arr_return[$value[$key_name]]['data_list'][] = $value;
        }
        sort($arr_return);
        return $arr_return;
    }

    /**
     * 校验是否有空参数，有则返回false
     * @param $arr
     * @return bool
     */
    public static function CheckNullParam($arr)
    {
        foreach($arr as $value){
            if(!isset($value)){
                return false;
            }
        }
        return true;
    }

    /**
     * 对unicode码再进行解码
     * @param $str
     * @return mixed
     */
    public static function DecodeUnicode($str)
    {
        return preg_replace_callback('/\\\\u([0-9a-f]{4})/i',
            create_function(
                '$matches',
                'return mb_convert_encoding(pack("H*", $matches[1]), "UTF-8", "UCS-2BE");'
            ),
            $str);
    }

    /**
     * 获取微秒级时间
     * @return float
     */
    public static function getMillisecond()
    {
        list($t1, $t2) = explode(' ', microtime());
        return (float)sprintf('%.0f',(floatval($t1)+floatval($t2))*1000);
    }

    /**
     * @param string $url 请求的地址.
     * @param array $data 发送的请求数据.
     * @param string $type 根据type判断发送的数据格式.
     * @param int $timeout 等待时间.
     * @return mixed|void
     */
    public static function postDataByPost($url = '', $data = [], $type='json', $timeout = 10)
    {

        if(empty( $url )){
            return '';
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回的内容作为变量储存，而不是直接输出。这个时候就必需设置curl的CURLOPT_RETURNTRANSFER选项为1或true.

        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

        if( $data != '' && !empty( $data ) ){
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Content-Length: ' . strlen(json_encode($data))));
        }
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        // dump($url);
        // dump($data);
        $result = curl_exec($ch);
        curl_close($ch);

        return $result;
    }

    /**
     * 模拟支付宝发送请求.
     * @param string $url 请求的地址.
     * @param array $data 发送的请求数据.
     * @param string $type 根据type判断发送的数据格式.
     * @param int $timeout 等待时间.
     * @return mixed|void
     */
    public static function curlPostData($url = '', $data = [], $type='json', $timeout = 10)
    {

        if(empty( $url )){
            return '';
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
//        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回的内容作为变量储存，而不是直接输出。这个时候就必需设置curl的CURLOPT_RETURNTRANSFER选项为1或true.

        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15G77 NebulaSDK/1.8.100112 Nebula PSDType(1)AlipayDefined(nt:4G, ws:320|504|2.0) AliApp(AP/10.1.32.600)AlipayClient/10.1.32.600 Alipay Language/zh-Hans');
        // 跳过证书检查
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        // 不从证书中检查SSL加密算法是否存在
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        $result = curl_exec($ch);

        curl_close($ch);

        return $result;
    }



    /**
     * 去掉数组中值的两边空格.
     * @param array $data
     * @return array
     */
    public static function ArrayTrim($data=[])
    {
        if(empty($data))
        {
            return [];
        }

        foreach ($data as $k => $v)
        {
            if(!is_array($v))
            {
                $data[$k] = trim($v);
            }else{
                $data[$k] = self::ArrayTrim($v);
            }
        }

        return $data;
    }




    public static function getIpData($url,$header){
        $ch = curl_init();
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
        curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
        curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,2);
        $handles = curl_exec($ch);
        curl_close($ch);
        return $handles;
    }


}